#include "sharpiot.h"
#include <string.h>
#include <stdlib.h>

SharpIotPack::SharpIotPack(void)
{
    pid = 0;
    type = TYPE_NONE;
    timestamp = 0;
    value.String = NULL;
}

SharpIotPack::SharpIotPack(const uint8_t *pdata, uint16_t size)
{
    type = TYPE_NONE;
    parse(pdata, size);
}

SharpIotPack::SharpIotPack(SharpIot_t type, const uint8_t *pdata, uint16_t size)
{
    this->pdata = pdata;
    this->size = size;
    parse(type, pdata, size);
}

uint8_t *SharpIotPack::data_find_char(const uint8_t *pdata, uint16_t size, char c)
{
    uint8_t *ptr;
    for (ptr = (uint8_t*)pdata; ptr < pdata + size; ptr++)
    {
        if (*ptr == c)
        {
            return ptr;
        }
    }
    return 0;
}

inline uint8_t *SharpIotPack::skip_space(const uint8_t *pdata, uint16_t size, uint8_t *ptr)
{
    while ((*ptr == ' ' || *ptr == '\n' || *ptr == '\r') &&
        ptr < pdata + size) ptr++; // 去掉空格
    return ptr;
}

bool SharpIotPack::parse(SharpIot_t type, const uint8_t *pdata, uint16_t size)
{
    //{  "Pid": 15,  "Timestamp": "1714653791",  "Value": "on"}
    uint8_t *ptr;
    ptr = data_find_char(pdata, size, '{');
    if (ptr == 0) return false;
    ptr = data_find_char(ptr + 1, size - (ptr - pdata), ':');
    if (ptr == 0) return false;
    ptr = skip_space(pdata, size, ptr + 1);// 去掉空格
    // Pid
    this->pid = atoi((char*)ptr);
    ptr = data_find_char(ptr + 1, size - (ptr - pdata), ':');
    if (ptr == 0) return false;
    ptr = skip_space(pdata, size, ptr + 1);// 去掉空格
    if (*ptr != '"') return false;
    ptr++; // 跳过引号
    // Timestamp
    this->timestamp = atoi((char*)ptr);
    ptr = data_find_char(ptr + 1, size - (ptr - pdata), ':');
    if (ptr == 0) return false;
    ptr = skip_space(pdata, size, ptr + 1);// 去掉空格
    if (*ptr != '"') return false;
    ptr++; // 跳过引号
    // Value
    switch (type)
    {
    case TYPE_NONE:
        this->value.String = (char*)ptr;
        break;
    case TYPE_BOOL:
        this->value.Bool = (ptr[0] == 'o' && ptr[1] == 'n') ? true : false;
        break;
    case TYPE_INT:
        this->value.Int = atoi((char*)ptr);
        break;
    case TYPE_FLOAT:
			  this->value.Float = atof((char*)ptr);
				break;
    case TYPE_DOUBLE:
        this->value.Double = atof((char*)ptr);
        break;
    case TYPE_STRING:
        this->value.String = (char*)ptr;
        break;
    default:
        return false;
    }
    return false;
}

bool SharpIotPack::parse(const uint8_t *pdata, uint16_t size)
{
    return parse(TYPE_NONE, pdata, size);
}

uint32_t SharpIotPack::getTimestamp(void)
{
    return this->timestamp;
}
uint16_t SharpIotPack::getPid(void)
{
    return this->pid;
}
float SharpIotPack::getFloat(void)
{
    if (this->type == TYPE_FLOAT)
    {
        return this->value.Float;
    }
    else if (this->type == TYPE_NONE && this->value.String != NULL)
    {
        this->type = TYPE_FLOAT;
        this->value.Float = atof(this->value.String);
        return this->value.Float;
    }
    return 0;
}
int SharpIotPack::getInt(void)
{
    if (this->type == TYPE_INT)
    {
        return this->value.Int;
    }
    else if (this->type == TYPE_NONE && this->value.String != NULL)
    {
        this->type = TYPE_INT;
        this->value.Int = atoi(this->value.String);
        return this->value.Int;
    }
    return 0;
}
bool SharpIotPack::getBool(void)
{
    if (this->type == TYPE_BOOL)
    {
        return this->value.Bool;
    }
    else if (this->type == TYPE_NONE && this->value.String != NULL)
    {
        this->type = TYPE_BOOL;
        this->value.Bool = (this->value.String[0] == 'o' && this->value.String[1] == 'n') ? true : false;
        return this->value.Bool;
    }
    return false;
}
const char *SharpIotPack::getString(void)
{
    if (this->type == TYPE_STRING)
    {
        return this->value.String;
    }
    else if (this->type == TYPE_NONE && this->value.String != NULL)
    {
        this->type = TYPE_STRING;
        return this->value.String;
    }
    return NULL;
}
double SharpIotPack::getDouble(void)
{
    if (this->type == TYPE_DOUBLE)
    {
        return this->value.Double;
    }
    else if (this->type == TYPE_NONE && this->value.String != NULL)
    {
        this->type = TYPE_DOUBLE;
        return atof(this->value.String);
    }
    return 0;
}

